import electron, {
  contextBridge,
  ipcRenderer,
  IpcRendererEvent,
} from 'electron';

const apiKey = 'tm';
const osnKey = 'osn';
const api: any = {
  ipcRenderer,
  versions: process.versions,
};

contextBridge.exposeInMainWorld(apiKey, api);
let recording = false;
let recordingStartedAt: any = null;
let timer: any = null;

type IpcRendererListener = (
  event: IpcRendererEvent,
  ...args: unknown[]
) => void;
type ScreenshotsListener = (...args: unknown[]) => void;

const map = new Map<ScreenshotsListener, Record<string, IpcRendererListener>>();
const osnAPi: any = {
  on: (channel: string, fn: ScreenshotsListener) => {
    console.log('contextBridge on', fn);

    const listener = (event: IpcRendererEvent, ...args: unknown[]) => {
      console.log('contextBridge on', channel, fn, ...args);
      fn(event, ...args);
    };

    const listeners = map.get(fn) ?? {};
    listeners[channel] = listener;
    map.set(fn, listeners);

    ipcRenderer.on(`${channel}`, listener);
  },
  off: (channel: string, fn: ScreenshotsListener) => {
    console.log('contextBridge off', fn);

    const listeners = map.get(fn) ?? {};
    const listener = listeners[channel];
    delete listeners[channel];

    if (!listener) {
      return;
    }

    ipcRenderer.off(`${channel}`, listener);
  },
  async obsSourceInit(fuc) {
    ipcRenderer.on('obsSourceInit', (e, data) => {
      console.log(data);
      fuc && fuc(data);
    });
  },
  initOBS: async function initOBS() {
    const result = await ipcRenderer.invoke('recording-init');
    if (result) {
      // ipcRenderer.on('performanceStatistics', (_event, data) => {
      //   osnAPi.onPerformanceStatistics(data);
      // });
      ipcRenderer.on('resizePreview', () => {
        osnAPi.resizePreview();
      });
    }
  },

  initModal: function initModal(fuc) {
    ipcRenderer.on('initModal', (e, data) => {
      console.log(data);
      fuc && fuc(data);
    });
  },
  changeScene: async function changeScene(name: string) {
    await ipcRenderer.invoke('changeScene', name);
  },

  startRecording: async function startRecording() {
    const result = await ipcRenderer.invoke('recording-start');

    console.log('startRecording result:', result);

    return result;
  },

  stopRecording: async function stopRecording() {
    const result = await ipcRenderer.invoke('recording-stop');
    console.log('stopRecording result:', result);
    return result;
  },

  switchRecording: async function switchRecording() {
    if (recording) {
      recording = (await osnAPi.stopRecording()).recording;
    } else {
      recording = (await osnAPi.startRecording()).recording;
    }
    osnAPi.updateUI();
  },
  async getAllDisplays() {
    const allDis = await ipcRenderer.invoke('getAllDisplays');
    return allDis;
  },
  async getALlCameras() {
    const cameras = await ipcRenderer.invoke('getALlCameras');
    return cameras;
  },
  async getAllScene() {
    const result = await ipcRenderer.invoke('getAllScene');
    return result;
  },
  async getAllSource(scence) {
    const result = await ipcRenderer.invoke('getAllSource', scence);
    return result;
  },
  startTimer: function startTimer() {
    recordingStartedAt = Date.now();
    timer = setInterval(osnAPi.updateTimer, 100);
  },

  stopTimer: function stopTimer() {
    clearInterval(timer);
  },
  updateUI: async function updateUI() {
    console.log('on updateUI---------------------');
    const button = document.getElementById('rec-button');
    button.disabled = false;
    if (recording) {
      console.log('status: start');
      button.innerText = '⏹️ Stop recording';
      osnAPi.startTimer();
    } else {
      console.log('status: Stop');
      button.innerText = '⏺️ Start recording';
      osnAPi.stopTimer();
    }

    await osnAPi.getStream();

    const displaySelect = document.getElementById('displaySelect');
    const allDisplays = await osnAPi.getAllDisplays();
    allDisplays.forEach(function (dispaly, index) {
      displaySelect.options.add(
        new Option(dispaly.size.height + '*' + dispaly.size.width, index),
      );
    });
    //设置主显示器
    displaySelect.selectedIndex = 0;
    osnAPi.displaySelectChange();

    const cameras = await ipcRenderer.invoke('getALlCameras');
    const cameraSelect = document.getElementById('cameraSelect');
    cameras.forEach(function (camera) {
      cameraSelect.options.add(new Option(camera.name, camera.value));
    });

    const allScene = await ipcRenderer.invoke('getAllScene');
    console.log(allScene);

    const sceneSelect = document.getElementById('sceneSelect');
    allScene.forEach(function (scene) {
      sceneSelect.options.add(new Option(scene.name, scene.name));
    });
    sceneSelect.selectedIndex = 0;

    const sourceSelect = document.getElementById('sourceSelect');
    if (allScene.length === 1) {
      allScene[0].items.forEach(function (item) {
        sourceSelect.options.add(new Option(item, item));
      });
    }
  },

  // 获取流数据
  getStream: async function getStream() {
    const rtmp_server = document.getElementById('rtmp_server');
    const rtmp_key = document.getElementById('rtmp_key');

    const streamSettings = await ipcRenderer.invoke('getSetting', {
      name: 'Stream',
    });

    streamSettings.forEach((subCate) => {
      subCate.parameters.forEach((parameter) => {
        switch (parameter.name) {
          case 'service': {
            break;
          }
          case 'server': {
            rtmp_server.value = parameter.currentValue;
            break;
          }
          case 'key': {
            rtmp_key.value = parameter.currentValue;
            break;
          }
        }
      });
    });
  },

  updateTimer: async function updateTimer() {
    const diff = Date.now() - recordingStartedAt;
    const timerElem = document.getElementById('rec-timer');
    const decimals = `${Math.floor((diff % 1000) / 100)}`;
    const seconds = `${Math.floor((diff % 60000) / 1000)}`.padStart(2, '0');
    const minutes = `${Math.floor((diff % 3600000) / 60000)}`.padStart(2, '0');
    const hours = `${Math.floor(diff / 3600000)}`.padStart(2, '0');
    timerElem.innerText = `${hours}:${minutes}:${seconds}.${decimals}`;
  },

  // ,openFolder:function openFolder() {
  //   shell.openPath(path.join(__dirname, 'videos'));
  // }

  setupPreview: async function setupPreview(previewRef) {
    const previewContainer = previewRef.currentValue;
    const preview = document.getElementById('preview');
    const { width, height, x, y } = previewContainer.getBoundingClientRect();
    const result = await ipcRenderer.invoke('preview-init', {
      width,
      height,
      x,
      y,
    });
    preview.style.width = `${result.width}px`;
    preview.style.x = `${result.x}px`;
  },

  resizePreview: async function resizePreview() {
    const previewContainer = document.getElementById('obsPreview');
    const preview = document.getElementById('preview');
    const { width, height, x, y } = previewContainer.getBoundingClientRect();
    const result = await ipcRenderer.invoke('preview-bounds', {
      width,
      height,
      x,
      y,
    });
    preview.style.width = `${result.width}px`;
    preview.style.x = `${result.x}px`;
  },

  // 保存设置
  saveSetting: async function saveSetting() {
    const server = document.getElementById('rtmp_server').value;
    const key = document.getElementById('rtmp_key').value;
    console.log(server, key);
    await ipcRenderer.invoke('update-rtmp', { server, key });
    await osnAPi.getStream();
  },

  // 获取setting
  getSetting: async function getSetting() {
    debugger;
    const cate = document.getElementById('OBSSettingsCategories');
    const result = await ipcRenderer.invoke('getSetting', {
      name: cate.options[cate.selectedIndex].text,
    });
    console.log(result);
  },

  // 选择摄像头
  cameraSelectChange: async function cameraSelectChange() {
    const select = document.getElementById('cameraSelect');
    const result = await ipcRenderer.invoke('cameraSelect', {
      id: select.options[select.selectedIndex].value,
    });
    console.log(result);
  },

  // 选择显示器
  displaySelectChange: async function displaySelectChange() {
    const select = document.getElementById('displaySelect');
    const result = await ipcRenderer.invoke('selectDisPlay', {
      id: select.options[select.selectedIndex].value,
    });
    console.log(result);
  },

  // 修改源数据
  updateSource: async function updateSource(sence, name, updateSetting) {
    const result = await ipcRenderer.invoke(
      'updateSource',
      sence,
      name,
      updateSetting,
    );
    console.log(result);
  },
  addSource: async function addSource() {
    await ipcRenderer.invoke('addSource');
  },

  // 是否直播
  streaming: async function streaming() {
    const streamingButton = document.getElementById('streaming');
    let status = Boolean(
      JSON.parse(localStorage.getItem('streaming_status') ?? '{"status":true}')
        .status,
    );
    if (!status) {
      console.log('开始直播');
      streamingButton.innerText = '结束直播';
    } else {
      console.log('结束直播');
      streamingButton.innerText = '开始直播';
    }
    await ipcRenderer.invoke('toggleStreaming', status);
    localStorage.setItem(
      'streaming_status',
      JSON.stringify({ status: !status }),
    );
    console.log('修改后', localStorage.getItem('streaming_status'));
  },
  initOsn: async function initOsn() {
    // const previewContainer = document.querySelector('#preview')
    // const currentWindow = remote.getCurrentWindow();
    // currentWindow.on('resize', osnAPi.resizePreview);
    // document.addEventListener('scroll', ()=>{
    //   console.log('scroll');

    //   osnAPi.resizePreview()
    // });
    // const ro = new ResizeObserver(osnAPi.resizePreview);
    // ro.observe(previewContainer);

    try {
      // await osnAPi.initOBS();
      // await osnAPi.setupPreview();
      // await osnAPi.updateUI();
    } catch (err) {
      console.log(err);
    }
  },
  getMousePosition: async function getMousePosition() {
    await ipcRenderer.invoke('getMousePosition', {});
  },
  mousePosition: async function mousePosition(event: any, data: any) {
    electron.ipcRenderer.on('mousePosition', (e, data) => {
      console.log(data);
    });
  },
  mouseMovePosition: function mouseMovePosition(
    senceSelect: string,
    sourceSelect: string,
    clientX: number,
    clientY: number,
    scaleFactor: number,
  ) {
    ipcRenderer.invoke(
      'mouseMovePosition',
      senceSelect,
      sourceSelect,
      clientX,
      clientY,
      scaleFactor,
    );
  },
  selectSource: function selectSource(
    senceSelect: string,
    sourceSelect: string,
  ) {
    ipcRenderer.invoke('selectSource', senceSelect, sourceSelect);
  },
  changeMouseCursor: async function changeMouseCursor(type: string) {
    const previewContainer = document.getElementById('preview');
    previewContainer.style.cursor = `${type}`;
  },
  coordinateDifference: function coordinateDifference(
    senceSelect: string,
    sourceSelect: string,
    clientX: number,
    clientY: number,
    leftMargin: number,
    scale: number,
  ) {
    ipcRenderer.invoke(
      'coordinateDifference',
      senceSelect,
      sourceSelect,
      clientX,
      clientY,
      leftMargin,
      scale,
    );
  },
  uploadVideo: function uploadVideo(peerServer: string, authorization: string) {
    ipcRenderer.invoke('uploadVideo', peerServer, authorization);
  },
  shareVideo: function (callback: (...args: any) => void) {
    ipcRenderer.on('shareVideo', (e, args) => {
      callback(...args);
    });
  },
  chatMessage: function (callback: (...args: any) => void) {
    ipcRenderer.on('chatMessage', (e, args) => {
      callback(...args);
    });
  },
  getInviteUser: function (callback: (...args: any) => void) {
    ipcRenderer.on('getInviteUser', (e, args) => {
      callback(...args);
    });
  },
  inviteUser: function (callback: (...args: any) => void) {
    ipcRenderer.on('inviteUser', (e, args) => {
      callback(...args);
    });
  },
  forceOut: function (callback: (...args: any) => void) {
    ipcRenderer.on('forceOut', (e, args) => {
      callback(...args);
    });
  },

  setLiving: function (callback: (e, args: boolean) => void) {
    ipcRenderer.on('setLiving', (e, args) => {
      callback(e, args);
    });
  },
  updatePatientActive: function (callback: (e, args: any) => void) {
    ipcRenderer.on('updatePatientActive', (e, args) => {
      callback(e, args);
    });
  },
  stopControlRecord: function (callback: (e, args: any) => void) {
    ipcRenderer.on('stopControlRecord', (e, args) => {
      callback(e, args);
    });
  },
  getAttendedList: function (callback: (...args: any) => void) {
    ipcRenderer.on('getAttendedList', (e, args) => {
      callback(...args);
    });
  },
  getAppAndStream: function (callback: (...args: any) => void) {
    ipcRenderer.on('getAppAndStream', (e, args) => {
      callback(...args);
    });
  },
  updateVideoStatus: function (callback: (...args: any) => void) {
    ipcRenderer.on('updateVideoStatus', (e, args) => {
      callback(...args);
    });
  },
  updateAudioStatus: function (callback: (...args: any) => void) {
    ipcRenderer.on('updateAudioStatus', (e, args) => {
      callback(...args);
    });
  },
  pullReceive: function (callback: (...args: any) => void) {
    ipcRenderer.on('pullReceive', (e, args) => {
      callback(...args);
    });
  },
  pullRemove: function (callback: (...args: any) => void) {
    ipcRenderer.on('pullRemove', (e, args) => {
      callback(...args);
    });
  },
  stopShare: function (callback: (...args: any) => void) {
    ipcRenderer.on('stopShare', (e, args) => {
      callback(...args);
    });
  },
  closeWindow: function (callback: (...args: any) => void) {
    ipcRenderer.on('closeWindow', (e, args) => {
      callback(...args);
    });
  },
  changeEmcee: function (callback: (...args: any) => void) {
    ipcRenderer.on('changeEmcee', (e, args) => {
      callback(...args);
    });
  },
  meetingRemind: function (callback: (...args: any) => void) {
    ipcRenderer.on('meetingRemind', (e, args) => {
      callback(...args);
    });
  },
  setToggleEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('setToggleEvents', (e, args) => {
      callback(...args);
    });
  },
  setVolumeClickEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('setVolumeClickEvents', (e, args) => {
      callback(...args);
    });
  },
  setCameraClickEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('setCameraClickEvents', (e, args) => {
      callback(...args);
    });
  },
  setChatShowEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('setChatShowEvents', (e, args) => {
      callback(...args);
    });
  },
  setInviteUserShowEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('setInviteUserShowEvents', (e, args) => {
      callback(...args);
    });
  },
  stopShareReceive: function (callback: (...args: any) => void) {
    ipcRenderer.on('stopShareReceive', (e, args) => {
      callback(...args);
    });
  },
  meetingShareRecordEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('meetingShareRecordEvents', (e, args) => {
      callback(...args);
    });
  },
  stopWhiteboardOperationBar: function (callback: (...args: any) => void) {
    ipcRenderer.on('stopWhiteboardOperationBar', (e, args) => {
      callback(...args);
    });
  },
  changeVolume: function (callback: (...args: any) => void) {
    ipcRenderer.on('changeVolume', (e, args) => {
      callback(...args);
    });
  },
  changeVideo: function (callback: (...args: any) => void) {
    ipcRenderer.on('changeVideo', (e, args) => {
      callback(...args);
    });
  },
  setRecordClickEvents: function (callback: (...args: any) => void) {
    ipcRenderer.on('setRecordClickEvents', (e, args) => {
      console.log('preload---set-recordClick-events', args);
      callback(...args);
    });
  },
  changeRecord: function (callback: (...args: any) => void) {
    ipcRenderer.on('changeRecord', (e, args) => {
      callback(...args);
    });
  },
  changMyselfMeetingStatus: function (callback: (...args: any) => void) {
    ipcRenderer.on('changMyselfMeetingStatus', (e, args) => {
      callback(...args);
    });
  },
};
contextBridge.exposeInMainWorld(osnKey, osnAPi);
